﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Xml.Serialization;
using ProgramMain.Layers;

namespace ProgramMain.NetVis
{

    public class LineConnectionRange
    {
        public LineConnectionRange(){}

        public LineConnectionRange(FibreRange fibre1, FibreRange fibre2, Layers.VisLayer vis, bool isConnectionIn, DCalckHorizont calckHorizont)
        {
            Vis = vis;
            IsConnectionIn = isConnectionIn;
            CalckHorizont = calckHorizont;
            Fibre1 = fibre1;
            Fibre2 = fibre2;
            _section = new List<SectionConnectionRange>();
            Fibre1ID = fibre1.FibreID;
            Fibre2ID = fibre2.FibreID;
            Fibre1.ShiftFibreEvent += ShiftEvent;
            Fibre2.ShiftFibreEvent += ShiftEvent;

            LineConnectionRange lineConnectionRange = Vis != null
                                                          ? Vis.GetConnectionFromXmlByFibreID(Fibre1ID, Fibre2ID)
                                                          : null;
            if (lineConnectionRange == null)
            SetConnectionPoint();
            else
            {
                SetConnectionPoint(lineConnectionRange);
            }
        }

        private bool _lineActivite;
         [XmlIgnore]
        public bool LineActivite
        {
            get { return _lineActivite; }
            set
            {
                if (_lineActivite != value)
                {
                    _lineActivite = value;
                    for (int i = 0; i < _section.Count; i++)
                    {
                        _section[i].IsActive = value;
                    }
                }
            }
        }
        [XmlIgnore]
        public Layers.VisLayer Vis { get; private set; }

        private List<DiamondRange> _points = new List<DiamondRange>();

        public List<SectionConnectionRange> _section { get; set; }

        public void Draw(Graphics layer)
        {
            foreach (SectionConnectionRange item in _section)
                item.Draw(layer);

            foreach (DiamondRange item in _points)
                item.Draw(layer);
        }
         [XmlIgnore]
        public FibreRange Fibre1 { get; private set; }
         [XmlIgnore]
        public FibreRange Fibre2 { get; private set; }
         [XmlIgnore]
        public int LineConnectionID { get; set; }
        
        public int Fibre1ID { get; set; }
        public int Fibre2ID { get; set; }

        private bool IsConnectionIn { get; set; }

        public Point Point1 { get; set; }
        public Point Point2 { get; set; }

         [XmlIgnore]
        public DCalckHorizont CalckHorizont { get; set; }

          private void SetConnectionPoint(LineConnectionRange lineConnectionRange)
          {
              lineConnectionRange._section.ForEach(ls =>CreateSection(this,new ShiftConnection(ls.VirtualPoint1,ls.VirtualPoint2)));
          }
        private void SetConnectionPoint()
        {
            Point1 = IsConnectionIn ? Fibre1.VirtualConnectionPointIn : Fibre1.VirtualConnectionPointOut;
            Point2 = IsConnectionIn ? Fibre2.VirtualConnectionPointIn : Fibre2.VirtualConnectionPointOut;
            if(Vis == null) return;
            if (IsConnectionIn)
            {
                CreateSection(this, new ShiftConnection(Point1, Point2));
            }
            else
            {

               int y = CalckHorizont == null ? (Point1.Y + Point2.Y)/2 : CalckHorizont(Fibre1, Fibre2);
                // int y = (Point1.Y + Point2.Y)/2;
                Point pf1 = new Point(Point1.X, y);
                Point pf2 = new Point(Point2.X, y);

                CreateSection(this, new ShiftConnection(Point1, pf1));
                CreateSection(this, new ShiftConnection(pf1, pf2));
                CreateSection(this, new ShiftConnection(pf2, Point2));
            }
        }

        private void CreateDiamond(Point point)
        {
            DiamondRange diamondRange = new DiamondRange(Vis) { VirtualPoint = point };
            diamondRange.ShiftDiamodEvent += ShiftEvent;
            _points.Add(diamondRange);
        }

        private void CreateSection(object sender, ShiftConnection e)
        {
            int staticPoint = 0;
            SectionConnectionRange sectionConnectionRange = new SectionConnectionRange(Vis) { Ovner = this };
            if (_isPointsFibre(e.PointOld)) staticPoint = 1;
            if (_isPointsFibre(e.PointNew)) staticPoint = 2;
            sectionConnectionRange.SetPoints(e.PointOld, e.PointNew, staticPoint);
            sectionConnectionRange.IsActive = LineActivite;
            sectionConnectionRange.ShiftConnectionEvent += ShiftEvent;
            sectionConnectionRange.Ovner = this;
            sectionConnectionRange.CreateSectionEvent += new EventHandler<ShiftConnection>(sectionConnectionRange_CreateSectionEvent);
            sectionConnectionRange.DeleteSectionEvent += new EventHandler<ShiftConnection>(sectionConnectionRange_DeleteSectionEvent);
            _section.Add(sectionConnectionRange);

            if ((from q in _points where q.VirtualPoint == e.PointOld select q).Count() == 0 && !_isPointsFibre(e.PointOld))
            { CreateDiamond(e.PointOld); }

            if ((from q in _points where q.VirtualPoint == e.PointNew select q).Count() == 0 && !_isPointsFibre(e.PointNew))
            { CreateDiamond(e.PointNew); }

            if (_isPointsFibre(e.PointOld)) Point1 = e.PointOld;
            if (_isPointsFibre(e.PointNew)) Point2 = e.PointNew;
        }

        private void sectionConnectionRange_DeleteSectionEvent(object sender, ShiftConnection e)
        {
            SectionConnectionRange section1 = sender as SectionConnectionRange;
            if (section1 == null) return;

            List<SectionConnectionRange> sections = new List<SectionConnectionRange>();
            sections.AddRange(from q in _section
                              where (q.VirtualPoint1 == e.PointOld || q.VirtualPoint2 == e.PointOld)
                             && (!q.Equals(section1))
                              select q);
            sections.AddRange(from q in _section
                              where (q.VirtualPoint1 == e.PointNew || q.VirtualPoint2 == e.PointNew)
                             && (!q.Equals(section1))
                              select q);
            if (sections.Count != 2) return;

            SectionConnectionRange section2 = null;
            if (sections[0].StaticPoint > 0 && sections[1].StaticPoint == 0) section2 = sections[1];
            else if (sections[1].StaticPoint > 0 && sections[0].StaticPoint == 0) section2 = sections[0];
            else if (sections[0].StaticPoint == 0 && sections[1].StaticPoint == 0)
            {
                section2 = sections[0].Lenght() < sections[1].Lenght() ? sections[0] : sections[1];
            }
            if (section2 == null) return;

            Point o = Point.Empty;
            Point p1 = Point.Empty;
            Point p2 = Point.Empty;
            Point n = Point.Empty;
            if (section1.VirtualPoint1 == section2.VirtualPoint1) o = section1.VirtualPoint1;
            else if (section1.VirtualPoint1 == section2.VirtualPoint2) o = section1.VirtualPoint1;
            else if (section1.VirtualPoint2 == section2.VirtualPoint1) o = section1.VirtualPoint2;
            else if (section1.VirtualPoint2 == section2.VirtualPoint2) o = section1.VirtualPoint2;
            p1 = o + section1.GetVectorByPoint(o);
            p2 = o + section2.GetVectorByPoint(o);
            n = o + section1.GetVectorByPoint(o) + section2.GetVectorByPoint(o);
            if (o == Point.Empty || p1 == Point.Empty || p2 == Point.Empty || n == Point.Empty) return;

            (from q in _points where q.VirtualPoint == o select q).First().RemoveRectange();
            (from q in _points where q.VirtualPoint == p1 select q).First().RemoveRectange();

            section1.RemoveRectange();
            section2.RemoveRectange();

            ShiftEvent(this, new ShiftConnection(p1, n));
            ShiftEvent(this, new ShiftConnection(p2, n));
        }

        private bool _isPointsFibre(Point point)
        {
            if (Fibre1 != null)
            {
                if (Fibre1.VirtualConnectionPointIn == point || Fibre1.VirtualConnectionPointOut == point) return true;
            }

            if (Fibre2 != null)
            {
                if (Fibre2.VirtualConnectionPointIn == point || Fibre2.VirtualConnectionPointOut == point) return true;
            }
            return false;
        }

        private void ShiftEvent(object sender, ShiftConnection e)
        {
            SectionConnectionRange sectionEvent = null;
            try
            {
                if (sender is SectionConnectionRange)
                    sectionEvent = (SectionConnectionRange)sender;

                List<SectionConnectionRange> sections = new List<SectionConnectionRange>(from q in _section
                                                                                         where (q.VirtualPoint1 == e.PointOld || q.VirtualPoint2 == e.PointOld)
                                                                                         select q);

                for (int i = 0; i < sections.Count; i++)
                {
                    SectionConnectionRange s = sections[i];
                    if ((sectionEvent != null && !sectionEvent.Equals(s)) || sectionEvent == null)
                    {
                        if (s.VirtualPoint1 == e.PointOld) s.VirtualPoint1 = e.PointNew;
                        else if (s.VirtualPoint2 == e.PointOld) s.VirtualPoint2 = e.PointNew;
                    }
                }

                if (!(sender is DiamondRange))
                {

                    DiamondRange diamon = (from q in _points where q.VirtualPoint == e.PointOld select q).First();
                    diamon.VirtualPoint = e.PointNew;
                }
            }
            catch (Exception)
            {

            }
            Point1 = IsConnectionIn ? Fibre1.VirtualConnectionPointIn : Fibre1.VirtualConnectionPointOut;
            Point2 = IsConnectionIn ? Fibre2.VirtualConnectionPointIn : Fibre2.VirtualConnectionPointOut;
        }

        private SectionConnectionRange _activeSection = null;

        private bool PredicateDiamond(DiamondRange diamondRange)
        {
            if (_activeSection == null) return false;
            bool res = diamondRange.VirtualPoint == _activeSection.VirtualPoint1 || diamondRange.VirtualPoint == _activeSection.VirtualPoint2;
            if (res) res = diamondRange.RemoveRectange();
            return res;
        }

        void sectionConnectionRange_CreateSectionEvent(object sender, ShiftConnection e)
        {
            Point newpoint1 = Point.Empty;
            Point newpoint2 = Point.Empty;
            if (!(sender is SectionConnectionRange)) return;
            _activeSection = (SectionConnectionRange)sender;

            if (_activeSection.StaticPoint == 1)
            {
                newpoint1 = _activeSection.VirtualPoint1;
                Size V1 = new Size(_activeSection.VirtualPoint2.X - e.PointOld.X, _activeSection.VirtualPoint2.Y - e.PointOld.Y);
                Size V2 = new Size(e.PointNew.X - e.PointOld.X, e.PointNew.Y - e.PointOld.Y);
                newpoint2 = e.PointOld + V1 + (V1.Width == 0 ? V2 : Size.Empty);

            }
            else
            {
                newpoint1 = _activeSection.VirtualPoint2;
                Size V1 = new Size(_activeSection.VirtualPoint1.X - e.PointOld.X, _activeSection.VirtualPoint1.Y - e.PointOld.Y);
                Size V2 = new Size(e.PointNew.X - e.PointOld.X, e.PointNew.Y - e.PointOld.Y);
                if (sender is SectionConnectionRange && ((SectionConnectionRange)sender).StaticPoint!=0)
                    V2 = Size.Empty;
                newpoint2 = e.PointOld + V1 + V2;
            }
            if (newpoint1 == Point.Empty || newpoint2 == Point.Empty)
            {
                _activeSection = null;
                return;
            }
            _activeSection.RemoveRectange();
            (from q in _points where q.VirtualPoint == _activeSection.VirtualPoint1 || q.VirtualPoint == _activeSection.VirtualPoint2 select q).First().RemoveRectange();
            //  _points.RemoveAll(PredicateDiamond);
            if (_activeSection.StaticPoint == 1)
            {
                ShiftEvent(this, new ShiftConnection(_activeSection.VirtualPoint2, newpoint2));
            }
            else
            {
                ShiftEvent(this, new ShiftConnection(_activeSection.VirtualPoint1, newpoint2));
            }
            CreateSection(this, new ShiftConnection(newpoint1, e.PointOld));
            CreateSection(this, new ShiftConnection(e.PointOld, e.PointNew));
            CreateSection(this, new ShiftConnection(e.PointNew, newpoint2));

            _activeSection = null;
        }

        public int RemoveSection(SectionConnectionRange sectionConnectionRange)
        {
            return _section.RemoveAll(s => s.RangeID == sectionConnectionRange.RangeID);
        }

        public int RemoveDiamond(DiamondRange diamondRange)
        {
            return _points.RemoveAll(d => d.RangeID == diamondRange.RangeID);
        }
         [XmlIgnore]
        public double Lenght
        {
            get
            {
                int x = Fibre2.ConnectionPointOut.X - Fibre1.ConnectionPointOut.X;
                int y = Fibre2.ConnectionPointOut.Y - Fibre1.ConnectionPointOut.Y;
                try
                {
                    return Math.Sqrt(x * x + y * y);
                }
                catch (Exception)
                {

                    return 0;
                }
            }
        }
    }
}